import os
import datetime
import gzip
import zipfile
from django.conf import settings
from django_apscheduler.jobstores import DjangoJobStore
from apscheduler.schedulers.background import BackgroundScheduler

# 初始化调度器
scheduler = BackgroundScheduler()
scheduler.add_jobstore(DjangoJobStore(), "default")


def backup_database():
    """数据库备份任务"""
    # 备份文件存储路径
    backup_dir = os.path.join(settings.BASE_DIR, 'backups')
    os.makedirs(backup_dir, exist_ok=True)

    # 生成带时间戳的备份文件名
    timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
    db_name = settings.DATABASES['default']['NAME'].split('/')[-1].split('\\')[-1]
    backup_filename = f"{db_name}_{timestamp}.sql"
    backup_path = os.path.join(backup_dir, backup_filename)

    # 执行数据库备份
    if settings.DATABASES['default']['ENGINE'] == 'django.db.backends.mysql':
        user = settings.DATABASES['default']['USER']
        password = settings.DATABASES['default']['PASSWORD']
        host = settings.DATABASES['default']['HOST'] or 'localhost'
        port = settings.DATABASES['default']['PORT'] or '3306'
        cmd = f"mysqldump -h {host} -P {port} -u {user} -p{password} {db_name} > {backup_path}"
        os.system(cmd)

    elif settings.DATABASES['default']['ENGINE'] == 'django.db.backends.postgresql':
        user = settings.DATABASES['default']['USER']
        host = settings.DATABASES['default']['HOST'] or 'localhost'
        port = settings.DATABASES['default']['PORT'] or '5432'
        cmd = f"pg_dump -h {host} -p {port} -U {user} {db_name} > {backup_path}"
        os.environ['PGPASSWORD'] = settings.DATABASES['default']['PASSWORD']
        os.system(cmd)

    else:  # SQLite
        import shutil
        shutil.copy2(settings.DATABASES['default']['NAME'], backup_path)

    # 压缩备份文件
    with open(backup_path, 'rb') as f_in, gzip.open(f"{backup_path}.gz", 'wb') as f_out:
        f_out.writelines(f_in)
    os.remove(backup_path)

    # 清理旧备份
    clean_old_backups(backup_dir)


def clean_old_backups(backup_dir, days_to_keep=30):
    """清理过期备份"""
    cutoff = datetime.datetime.now() - datetime.timedelta(days=days_to_keep)
    for filename in os.listdir(backup_dir):
        if filename.endswith('.sql.gz') or filename.endswith('.zip'):
            file_path = os.path.join(backup_dir, filename)
            file_time = datetime.datetime.fromtimestamp(os.path.getctime(file_path))
            if file_time < cutoff:
                os.remove(file_path)




def backup_media_directory():
    """备份media目录到压缩文件"""
    try:
        # 备份配置
        backup_dir = os.path.join(settings.BASE_DIR, 'backups')
        source_dir = settings.MEDIA_ROOT  # 获取media目录路径
        days_to_keep = 30  # 保留30天的备份
        #删除临时文件
        temp_dir = os.path.join(settings.MEDIA_ROOT, 'temp')
        clean_temp_files(temp_dir)
        # 创建备份目录（如果不存在）
        os.makedirs(backup_dir, exist_ok=True)

        # 生成带时间戳的备份文件名
        timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
        backup_filename = f"media_backup_{timestamp}.zip"
        backup_path = os.path.join(backup_dir, backup_filename)

        # 压缩media目录
        with zipfile.ZipFile(backup_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
            for root, dirs, files in os.walk(source_dir):
                for file in files:
                    file_path = os.path.join(root, file)
                    # 计算相对路径，保持目录结构
                    arcname = os.path.relpath(file_path, source_dir)
                    zipf.write(file_path, arcname=arcname)

        print(f"Media backup completed: {backup_filename}")

        # 清理旧备份
        clean_old_backups(backup_dir, days_to_keep)

    except Exception as e:
        print(f"Media backup failed: {str(e)}")


def clean_temp_files(temp_dir):
    """清理临时文件，一般开机就清洗"""
    for filename in os.listdir(temp_dir):
        file_path = os.path.join(temp_dir, filename)
        os.remove(file_path)
'''
func=scheduled_job(self,trigger,
        args=None,
        kwargs=None,
        id=None,
        name=None,
        misfire_grace_time=undefined,
        coalesce=undefined,
        max_instances=undefined,
        next_run_time=undefined,
        jobstore="default",
        executor="default",
        **trigger_args,)
@trigger "cron" 指定任务的调度类型为 cron 表达式模式，用于按固定的时间规则重复执行任务（如每天、每周、每月的特定时间）。
        "interval" 按固定时间间隔执行（如每 2 小时、每 30 分钟）要用复数 weeks/days/hours/minutes/seconds
        "date" 只在指定的日期时间执行一次（一次性任务）

@args  时间规则参数：hour=19, minute=12，
        year=2023 或者year=*(每年)
        month=1  (1-12月) */2（每 2 个月）
        day=6  (1-31日)  L（当月最后一天）
        week
        day_of_week=0  (0-6周日到周六)
@id    是任务的唯一标识符，必须在整个调度器中唯一。
'''
# 添加定时任务（每天19:12执行）
@scheduler.scheduled_job("cron", hour=19, minute=12, id="database_backup")
def scheduled_backup():
    backup_database()

# 添加定时任务（每周六执行）
@scheduler.scheduled_job("cron", day_of_week=6, id="media_backup")
def scheduled_media_backup():
    backup_media_directory()

# 添加定时任务（每周六执行）
@scheduler.scheduled_job("interval", minutes=60, id="clear_temp")
def scheduled_clear_temp():
    # 临时文件
    temp_dir = os.path.join(settings.MEDIA_ROOT, 'temp')
    clean_temp_files(temp_dir)
# 启动调度器
scheduler.start()